package com.spark.lola.logistics.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.spark.lola.feign.SupFeignService;
import com.spark.lola.logistics.constant.LogisticsConstant;
import com.spark.lola.logistics.entity.*;
import com.spark.lola.logistics.mapper.*;
import com.spark.lola.logistics.service.*;
import com.spark.lola.logistics.vo.MatchToOrderLocationVo;
import com.spark.lola.logistics.vo.OrderCountStatisticVo;
import com.spark.lola.logistics.vo.OrderInfoVo;
import com.spark.lola.logistics.vo.OrderStatisticVo;
import com.spark.lola.statistics.dto.DealLogisticsChange;
import com.spark.lola.support.core.vo.SelectMap;
import com.spark.lola.support.common.entity.ShiroUser;
import com.spark.lola.support.common.util.DataBeanUtils;
import com.spark.lola.support.common.util.NumberUtil;
import com.spark.lola.support.mybatis.entity.PageParam;
import com.spark.lola.support.mybatis.entity.QueryParam;
import com.spark.lola.support.mybatis.service.impl.BaseServiceImpl;
import com.spark.lola.support.wms.cache.CollectionCache;
import com.spark.lola.support.wms.constant.KafkaTopic;
import com.spark.lola.support.wms.constant.OrderType;
import com.spark.lola.support.wms.dto.OrderDto;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: Zhi-peng wang
 * @date: 2020/04/27 16:03
 * 货运单业务实现
 **/
@Service
public class LogisticsOrderInfoServiceImpl extends BaseServiceImpl<LogisticsOrderInfoMapper, OrderInfo> implements LogisticsOrderInfoService {

    private static final Logger logger = LoggerFactory.getLogger(LogisticsOrderInfoServiceImpl.class);

    @Autowired
    private LogisticsOrderInfoMapper logisticsOrderInfoMapper;

    @Autowired
    private LogisticsOrderProductMapper logisticsOrderProductMapper;

    @Autowired
    private LogisticsOrderProcessMapper logisticsOrderProcessMapper;

    @Autowired
    private CarInfoMapper carInfoMapper;

    @Autowired
    private LogisticsOrderProductService logisticsOrderProductService;

    @Autowired
    private LocationInfoService locationInfoService;

    @Autowired
    private CarSubscribeService carSubscribeService;

    @Autowired
    private SupFeignService supFeignService;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    @Override
    public IPage<OrderInfoVo> findPage(QueryParam<OrderInfoVo> queryParam) {
        PageParam<OrderInfoVo> pageParam = queryParam.toPageParam();
        return logisticsOrderInfoMapper.findPage(pageParam.getPage(), pageParam.getEntityWrapper());
    }

    /**
     * @description: 获取货运单全部信息
     * @param: orderInfoId 货运单id
     * @return: OrderInfo 货运单信息
     * @author: wzp
     * @date: 2020/4/30
     */
    @Override
    public OrderInfo findInfo(long orderInfoId) throws Exception {
        // 获取货运单基本信息
        OrderInfo orderInfo = logisticsOrderInfoMapper.selectById(orderInfoId);
        if (orderInfo == null) {
            throw new Exception("订单id错误");
        }
        // 获取货运单商品信息
        List<OrderProduct> orderProductList = logisticsOrderProductMapper.findByOrderId(orderInfoId);
        // 获取操作流程信息
        List<OrderProcess> orderProcessList = logisticsOrderProcessMapper.findByOrderId(orderInfoId);
        // 获取创建人信息
        orderInfo.setDriverInfo(CollectionCache.employees.get(orderInfo.getCreatorId()));
        // 已定价获取纸厂信息
        if (orderInfo.getStatus() > LogisticsConstant.OrderStatus.ALREADY_RECEIVING) {
            orderInfo.setLocationInfo(locationInfoService.getById(orderInfo.getLocationInfoId()));
        }
        // 获取车辆信息
        if (orderInfo.getCreatorId() != 528L) {
            CarInfo carInfo = carInfoMapper.selectById(orderInfo.getCarId());
            orderInfo.setCarInfo(carInfo);
        }
        orderInfo.setOrderProductList(orderProductList);
        orderInfo.setOrderProcessList(orderProcessList);
        return orderInfo;
    }

    public MatchToOrderLocationVo matchToOrderLocation(long createId) {
        return logisticsOrderInfoMapper.queryMatchTo(createId);
    }

    /**
     * @description: 保存货运单信息
     * @param: orderInfo 货运单信息
     * @param: shiroUser 用户信息
     * @return: OrderInfo 货运单信息
     * @author: wzp
     * @date: 2020/4/30
     */
    @Override
    public OrderInfo saveOrder(OrderInfo orderInfo, ShiroUser shiroUser) throws Exception {
        Long orderId = orderInfo.getId();
        String logAction = orderId == null ? "创建" : "修改";
        String orderNo = orderId == null ? NumberUtil.getOrderIdByTime("L") : orderInfo.getNo();
        logger.info("===={}货运单【{}】{}人【{}】===START===", logAction, orderNo, logAction, shiroUser.getLoginNo());
        // 判定信息健全
        List<OrderProduct> orderProductList = orderInfo.getOrderProductList();
        if (CollectionUtils.isEmpty(orderProductList)) {
            logger.info("====未添加货运商品信息===END===");
            throw new Exception("未添加货运商品信息");
        }
        // 保存货运单信息
        OrderInfo model = saveOrderInfo(orderInfo, orderNo, shiroUser.getId());
        // 批量保存货运单商品信息
        OrderInfo info = saveOrderProduct(orderProductList, model.getId());
        info.setId(model.getId());
        info.setVersion(model.getVersion());
        // 保存商品信息到货运单
        if (logisticsOrderInfoMapper.updateById(info) == 0) {
            logger.info("====保存商品信息到货运单 失败===END===");
            throw new Exception("保存商品ids到货运单失败");
        }
//        // 增量更新地址信息库
//        if (orderId == null) {
//            saveLocation(orderInfo.getLocationInfoList());
//        }
        // 添加操作记录
        String actionMsg = addOrderProcess(model.getId(), model.getNo(), shiroUser, model.getStatus(), logAction);
        model.setOrderProductList(orderProductList);
        model.setTransportTotal(info.getTransportTotal());
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // kafka推送
                        sendOrderChange(model, "运输单创建成功！", actionMsg);
                    }
                });
        logger.info("====保存货运单信息 成功===END===");
        return model;
    }

    @Override
    public OrderInfo saveEmptyOrder(OrderInfo orderInfo, ShiroUser shiroUser) throws Exception {
        orderInfo.setNo(NumberUtil.getOrderIdByTime("L"));
        orderInfo.setIsEmpty(LogisticsConstant.OrderIsEmpty.YES);
        logisticsOrderInfoMapper.insert(orderInfo);
        // 添加操作记录
        String actionMsg = addOrderProcess(orderInfo.getId(), orderInfo.getNo(), shiroUser, orderInfo.getStatus(), "创建");
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // kafka推送
                        sendOrderChange(orderInfo, "空车运输单创建成功！", actionMsg);
                    }
                });
        return orderInfo;
    }

    @Override
    public void deleteOrder(long orderId, ShiroUser shiroUser) throws Exception {
        OrderInfo orderInfo = logisticsOrderInfoMapper.selectById(orderId);
        logger.info("====货运单【{}】删除操作 操作人【{}】===START===", orderInfo.getNo(), shiroUser.getLoginNo());
        if (!orderInfo.getCreatorId().equals(shiroUser.getId())) {
            logger.info("====货运单删除操作（非法操作） 失败===END===");
            throw new Exception("非法操作");
        }
        if (orderInfo.getStatus() >= LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS) {
            logger.info("====货运单删除操作（已发货禁止删除） 失败===END===");
            throw new Exception("已发货禁止删除");
        }
        // 删除商品信息
        logger.info("====删除货运单商品信息 ===START===");
        if (logisticsOrderProductMapper.deleteByOrderId(orderId) == 0) {
            logger.info("====货运单商品信息删除 失败===END===");
            throw new Exception("货运单商品信息删除失败");
        }
        logger.info("====货运单商品信息删除 成功===END===");
        // 删除流程信息
        logger.info("====删除货运单流程信息 ===START===");
        if (logisticsOrderProcessMapper.deleteByOrderId(orderId) == 0) {
            logger.info("====货运单流程信息删除 失败===END===");
            throw new Exception("货运单流程信息删除失败");
        }
        logger.info("====货运单流程信息删除 成功===END===");
        // 删除货运单信息
        logger.info("====删除货运单信息 ===START===");
        if (logisticsOrderInfoMapper.deleteById(orderId) == 0) {
            logger.info("====货运单信息删除 失败===END===");
            throw new Exception("货运单信息删除失败");
        }
        logger.info("====货运单信息删除 成功===END===");
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // kafka推送
                        OrderProcess orderProcess = new OrderProcess();
                        orderProcess.setActionCode(-3);
                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        String nowDate = simpleDateFormat.format(new Date());
                        orderProcess.setInfo(String.format("员工【%s】%s 进行【删除】操作", shiroUser.getRealName(), nowDate));
                        sendOrderChange(orderInfo, shiroUser.getRealName() + "删除了运输单", JSONObject.toJSONString(orderProcess));
                    }
                });
    }

//    /**
//     * @description: 货运单审核
//     * @param: null
//     * @return:
//     * @author: wzp
//     * @date: 2020/4/30
//     */
//    @Override
//    public void audit(long orderId, ShiroUser shiroUser) throws Exception {
//        OrderInfo orderInfo = logisticsOrderInfoMapper.selectById(orderId);
//        logger.info("====货运单【{}】审核操作 操作人【{}】===START===", orderInfo.getNo(), shiroUser.getLoginNo());
//        if (!orderInfo.getCreatorId().equals(shiroUser.getId())) {
//            logger.info("====货运单审核操作 失败===END===");
//            throw new Exception("非法操作");
//        }
//        // 判断是否是待审核状态
//        if (orderInfo.getStatus() != LogisticsConstant.OrderStatus.WAIT_AUDIT) {
//            logger.info("====货运单审核操作 失败===END===");
//            throw new Exception("货运单发未处于待审核状态");
//        }
//        // 修改状态为待发货状态
//        OrderInfo info = new OrderInfo(orderInfo.getId(), LogisticsConstant.OrderStatus.WAIT_SHIPMENTS);
//        info.setVersion(orderInfo.getVersion());
//        int count = logisticsOrderInfoMapper.updateById(info);
//        if (count == 0) {
//            logger.info("====货运单审核操作 失败===END===");
//            throw new Exception("货运单审核操作失败");
//        }
//        // 添加操作记录
//        String actionMsg = addOrderProcess(orderInfo.getId(), orderInfo.getNo(), shiroUser, LogisticsConstant.OrderStatus.WAIT_SHIPMENTS, LogisticsConstant.OrderAction.CHECKING);
//        // kafka推送
//        sendOrderChange(orderInfo, actionMsg);
//        logger.info("====货运单审核操作 成功===END===");
//    }

    @Override
    public void cancel(long orderId, String msg, ShiroUser shiroUser) throws Exception {
        OrderInfo orderInfo = logisticsOrderInfoMapper.selectById(orderId);
        logger.info("====货运单【{}】取消操作 操作人【{}】===START===", orderInfo.getNo(), shiroUser.getLoginNo());
        if (!orderInfo.getCreatorId().equals(shiroUser.getId())) {
            logger.info("====货运单取消操作 失败===END===");
            throw new Exception("非法操作");
        }
        // 判断是否是在已发货/已完成/已取消
        if (orderInfo.getStatus() == LogisticsConstant.OrderStatus.ALREADY_INVALID ||
                orderInfo.getStatus() >= LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS) {
            logger.info("====货运单取消操作 失败===END===");
            throw new Exception("货运单发只有在发货之前可取消");
        }
        // 修改状态为取消状态
        OrderInfo info = new OrderInfo(orderInfo.getId(), LogisticsConstant.OrderStatus.ALREADY_INVALID);
        info.setVersion(orderInfo.getVersion());
        int count = logisticsOrderInfoMapper.updateById(info);
        if (count == 0) {
            logger.info("====货运单取消操作 失败===END===");
            throw new Exception("货运单取消操作失败");
        }
        // 添加操作记录
        String actionMsg = addOrderProcess(orderInfo.getId(), orderInfo.getNo(), shiroUser,
                LogisticsConstant.OrderStatus.ALREADY_INVALID,
                LogisticsConstant.OrderStatus.getLabel(LogisticsConstant.OrderStatus.ALREADY_INVALID));
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // kafka推送
                        sendOrderChange(orderInfo, shiroUser.getRealName() + "取消了运输单", actionMsg);
                    }
                });
        logger.info("====货运单取消操作 成功===END===");
    }

    /**
     * @description: 货运单确认发货
     * @param: null
     * @return:
     * @author: wzp
     * @date: 2020/4/30
     */
    @Override
    public void shipments(long orderId, String credentials, String remark, ShiroUser shiroUser) throws Exception {
        OrderInfo orderInfo = logisticsOrderInfoMapper.selectById(orderId);
        logger.info("====货运单【{}】确认发货操作 操作人【{}】===START===", orderInfo.getNo(), shiroUser.getLoginNo());
        if (!orderInfo.getCreatorId().equals(shiroUser.getId())) {
            logger.info("====货运单确认发货操作 失败===END===");
            throw new Exception("非法操作");
        }
        // 判断是否是待发货状态
        if (orderInfo.getStatus() != LogisticsConstant.OrderStatus.WAIT_SHIPMENTS) {
            logger.info("====货运单确认发货操作 失败===END===");
            throw new Exception("货运单发未处于待发货状态");
        }
        // 修改状态为已发货状态
        OrderInfo info = new OrderInfo(orderInfo.getId(), LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS);
        info.setVersion(orderInfo.getVersion());
        if (remark != null) {
            info.setRemark(remark);
        }
        int count = logisticsOrderInfoMapper.updateById(info);
        if (count == 0) {
            logger.info("====货运单确认发货操作 失败===END===");
            throw new Exception("货运单确认发货操作失败");
        }
        if (orderInfo.getCreatorId() != 528L) {
            // 当是直达车时
            if (orderInfo.getLineType() == LogisticsConstant.OrderLineType.TO_CAR) {
                logger.info("====添加驾驶员【{}】绑定的回头车预订信息 ===START===", shiroUser.getRealName());
                carSubscribeService.updateCarSubscribeUsed(orderInfo.getCreatorId());
                if (!carSubscribeService.addCarSubscribe(orderInfo, shiroUser)) {
                    logger.info("====添加回头车预订信息（更新失败） 失败===END===");
                    throw new Exception("添加回头车预订信息失败");
                }
                logger.info("====添加回头车预订信息 成功===END===");
            } else {
                // 修改当前驾驶员绑定的回头车预订记录为过期状态
                logger.info("====修改驾驶员【{}】绑定的回头车预订信息为过期 ===START===", shiroUser.getRealName());
                boolean flag = carSubscribeService.updateCarSubscribeUsed(orderInfo.getCreatorId());
                logger.info("====修改回头车预订过期 【{}】===END===", flag);
            }
        }
        // 添加操作记录
        String actionMsg = addOrderProcess(orderInfo.getId(), orderInfo.getNo(), shiroUser,
                LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS,
                LogisticsConstant.OrderStatus.getLabel(LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS),
                null, null, credentials, false);
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // kafka推送
                        sendOrderChange(orderInfo, "运输单已发车！", actionMsg);
                    }
                });
        logger.info("====货运单确认发货操作 成功===END===");
    }

    /**
     * @description: 货运单确认收货
     * @param: null
     * @return:
     * @author: wzp
     * @date: 2020/4/30
     */
    @Override
    public OrderInfo receiving(long orderId, String credentials, ShiroUser shiroUser) throws Exception {
        OrderInfo orderInfo = logisticsOrderInfoMapper.selectById(orderId);
        logger.info("====货运单【{}】确认收货操作 操作人【{}】===START===", orderInfo.getNo(), shiroUser.getLoginNo());
//        if (!orderInfo.getCreatorId().equals(shiroUser.getId())) {
//            logger.info("====货运单确认收货操作 失败===END===");
//            throw new Exception("非法操作");
//        }
        // 判断是否是已发货状态
        if (orderInfo.getStatus() != LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS) {
            logger.info("====货运单确认收货操作 失败===END===");
            throw new Exception("货运单发未处于已发货状态");
        }
        // 修改状态为已收货状态
        OrderInfo info = new OrderInfo(orderInfo.getId(), LogisticsConstant.OrderStatus.ALREADY_RECEIVING);
        info.setVersion(orderInfo.getVersion());
        int count = logisticsOrderInfoMapper.updateById(info);
        if (count == 0) {
            logger.info("====货运单确认收货操作 失败===END===");
            throw new Exception("货运单确认收货操作失败");
        }
        // 添加操作记录
        String actionMsg = addOrderProcess(orderInfo.getId(), orderInfo.getNo(), shiroUser,
                LogisticsConstant.OrderStatus.ALREADY_RECEIVING,
                LogisticsConstant.OrderStatus.getLabel(LogisticsConstant.OrderStatus.ALREADY_RECEIVING),
                null, null, credentials, false);
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // kafka推送
                        sendOrderChange(orderInfo, "运输单已签收！", actionMsg);
                    }
                });
        logger.info("====货运单确认收货操作 成功===END===");
        return orderInfo;
    }

    /**
     * @description: 货运单定价
     * @param: orderInfo 货运单信息
     * @return:
     * @author: wzp
     * @date: 2020/4/30
     */
    @Override
    public void pricing(long orderId, long locationId, BigDecimal price, BigDecimal actualAmount, String msg, String pageNo, ShiroUser shiroUser) throws Exception {
        OrderInfo orderInfo = logisticsOrderInfoMapper.selectById(orderId);
        logger.info("====货运单【{}】定价操作 操作人【{}】===START===", orderInfo.getNo(), shiroUser.getLoginNo());
        // 判断是否是已收货状态
        if (orderInfo.getStatus() != LogisticsConstant.OrderStatus.ALREADY_RECEIVING) {
            logger.info("====货运单定价操作 失败===END===");
            throw new Exception("货运单发未处于已收货状态");
        }
        if (price.compareTo(BigDecimal.ZERO) < 0 || actualAmount.compareTo(BigDecimal.ZERO) < 0) {
            logger.info("====货运单定价操作 失败===END===");
            throw new Exception("非法金额");
        }
        // 修改状态为代待核算状态
        OrderInfo info = new OrderInfo(orderInfo.getId(), LogisticsConstant.OrderStatus.ALREADY_GATHERING);
        info.setPageNo(pageNo);
        info.setLocationInfoId(locationId);
        info.setPrice(price);
        info.setActualAmount(actualAmount);
        info.setVersion(orderInfo.getVersion());
        if (logisticsOrderInfoMapper.updateById(info) == 0) {
            logger.info("====货运单定价操作 失败===END===");
            throw new Exception("货运单定价操作失败");
        }
        // 添加操作记录
        String actionMsg = addOrderProcess(orderInfo.getId(), orderInfo.getNo(), shiroUser,
                LogisticsConstant.OrderStatus.getLabel(LogisticsConstant.OrderStatus.ALREADY_GATHERING), msg);
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // 处理统计数据
                        DealLogisticsChange dealStatisticsChange = new DealLogisticsChange(
                                "pricing", new Date(), orderInfo.getCreatorId(), orderInfo.getCreatorId() == 528 ? 0 : orderInfo.getCarId(),
                                actualAmount.setScale(2, BigDecimal.ROUND_HALF_DOWN),
                                orderInfo.getTransportTotal().setScale(3, BigDecimal.ROUND_HALF_DOWN)
                        );
                        kafkaTemplate.send(KafkaTopic.STATISTICS_LOGISTICS_CHANGE, "order", JSONObject.toJSONString(dealStatisticsChange));
                        // kafka推送
                        sendOrderChange(orderInfo, shiroUser.getRealName() + "定价了运输单", actionMsg);
                    }
                });

        logger.info("====货运单定价操作 成功===END===");
    }

//    @Override
//    public void checkComputation(long orderId, BigDecimal actualAmount, ShiroUser shiroUser) throws Exception {
//        OrderInfo orderInfo = logisticsOrderInfoMapper.selectById(orderId);
//        logger.info("====货运单【{}】核算操作 操作人【{}】===START===", orderInfo.getNo(), shiroUser.getLoginNo());
//        // 判断是否是已收货状态
//        if (orderInfo.getStatus() != LogisticsConstant.OrderStatus.WAIT_CHECK) {
//            logger.info("====货运单核算操作（状态错误） 失败===END===");
//            throw new Exception("货运单发未处于已定价状态");
//        }
//        if (actualAmount.compareTo(BigDecimal.ZERO) <= 0) {
//            logger.info("====货运单核算操作（非法金额） 失败===END===");
//            throw new Exception("非法金额");
//        }
//        // 修改状态为代收款状态
//        OrderInfo info = new OrderInfo(orderInfo.getId(), LogisticsConstant.OrderStatus.ALREADY_GATHERING);
//        info.setActualAmount(actualAmount);
//        info.setVersion(orderInfo.getVersion());
//        int count = logisticsOrderInfoMapper.updateById(info);
//        if (count == 0) {
//            logger.info("====货运单核算操作（更新失败） 失败===END===");
//            throw new Exception("货运单核算操作失败");
//        }
//        // 添加操作记录
//        String actionMsg = addOrderProcess(orderInfo.getId(), orderInfo.getNo(), shiroUser, LogisticsConstant.OrderStatus.ALREADY_GATHERING, LogisticsConstant.OrderAction.ACCOUNTING);
//        // kafka推送
//        sendOrderChange(orderInfo, actionMsg);
//        logger.info("====货运单定价操作 成功===END===");
//    }

    @Override
    public void complete(long orderId, String credentials, ShiroUser shiroUser) throws Exception {
        OrderInfo orderInfo = logisticsOrderInfoMapper.selectById(orderId);
        logger.info("====货运单【{}】结算操作 操作人【{}】===START===", orderInfo.getNo(), shiroUser.getLoginNo());
        // 判断是否是已发货状态
        if (orderInfo.getStatus() != LogisticsConstant.OrderStatus.ALREADY_GATHERING) {
            logger.info("====货运单结算操作 失败===END===");
            throw new Exception("货运单未处于代收款状态");
        }
        // 修改状态为已收货状态
        OrderInfo info = new OrderInfo(orderInfo.getId(), LogisticsConstant.OrderStatus.ALREADY_COMPLETE);
        info.setVersion(orderInfo.getVersion());
        int count = logisticsOrderInfoMapper.updateById(info);
        if (count == 0) {
            logger.info("====货运单结算操作 失败===END===");
            throw new Exception("货运单结算操作失败");
        }
        // 添加操作记录
        String actionMsg = addOrderProcess(orderInfo.getId(), orderInfo.getNo(), shiroUser,
                LogisticsConstant.OrderStatus.ALREADY_COMPLETE,
                LogisticsConstant.OrderStatus.getLabel(LogisticsConstant.OrderStatus.ALREADY_COMPLETE), null, null, credentials, false);
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // kafka推送
                        DealLogisticsChange dealStatisticsChange = new DealLogisticsChange(
                                "complete", new Date(), orderInfo.getCreatorId(), orderInfo.getCarId(),
                                orderInfo.getActualAmount().setScale(2, BigDecimal.ROUND_HALF_DOWN),
                                orderInfo.getTransportTotal().setScale(3, BigDecimal.ROUND_HALF_DOWN)
                        );
                        kafkaTemplate.send(KafkaTopic.STATISTICS_LOGISTICS_CHANGE, "order", JSONObject.toJSONString(dealStatisticsChange));
                        sendOrderChange(orderInfo, shiroUser.getRealName() + "结算了运输单", actionMsg);
                    }
                });
        logger.info("====货运单结算操作 成功===END===");
    }

    @Override
    public void archive(long orderId, ShiroUser shiroUser) throws Exception {
        OrderInfo orderInfo = logisticsOrderInfoMapper.selectById(orderId);
        logger.info("====货运单【{}】归档操作 操作人【{}】===START===", orderInfo.getNo(), shiroUser.getLoginNo());
        // 判断是否是已完成状态
        if (orderInfo.getStatus() != LogisticsConstant.OrderStatus.ALREADY_COMPLETE) {
            logger.info("====货运单归档操作 失败===END===");
            throw new Exception("货运单未完成");
        }
        // 判断是否创建支出单
        if (orderInfo.getCreatorId() != 528 && orderInfo.getLineType() == LogisticsConstant.OrderLineType.TO_CAR &&
                orderInfo.getExpensesExists() == LogisticsConstant.ExpensesExists.NO_EXISTS) {
            logger.info("====货运单归档操作 失败===END===");
            throw new Exception("货运单未创建支出单，禁止归档");
        }
        // 判断是否是已归档
        if (orderInfo.getIsArchive() != LogisticsConstant.IsArchive.NO) {
            logger.info("====货运单归档操作 失败===END===");
            throw new Exception("货运单已归档");
        }
        // 修改状态为已收货状态
        OrderInfo info = new OrderInfo(LogisticsConstant.IsArchive.YES, orderInfo.getVersion(), orderInfo.getId());
        int count = logisticsOrderInfoMapper.updateById(info);
        if (count == 0) {
            logger.info("====货运单归档操作 失败===END===");
            throw new Exception("货运单归档操作失败");
        }
        logger.info("====货运单归档操作 成功===END===");
    }

    @Override
    public void rejected(long orderId, String msg, ShiroUser shiroUser) throws Exception {
        OrderInfo orderInfo = logisticsOrderInfoMapper.selectById(orderId);
        logger.info("====货运单【{}】驳回操作 操作人【{}】===START===", orderInfo.getNo(), shiroUser.getLoginNo());
        // 判断是否是已完成或已取消
        if (orderInfo.getStatus() == LogisticsConstant.OrderStatus.ALREADY_INVALID ||
                orderInfo.getStatus() == LogisticsConstant.OrderStatus.ALREADY_COMPLETE) {
            logger.info("====货运单驳回操作（已完成/已取消/禁止操作） 失败===END===");
            throw new Exception("货运单已完成/已取消禁止操作");
        }
        // 修改状态为代收款状态
        int newStatus = orderInfo.getStatus() - 1;
        logger.info("===更新订单状态 【{}】=>【{}】", LogisticsConstant.OrderStatus.getLabel(orderInfo.getStatus()),
                LogisticsConstant.OrderStatus.getLabel(newStatus));
        OrderInfo info = new OrderInfo(orderInfo.getId(), newStatus);
        info.setIsRejected(LogisticsConstant.IsRejected.YES);
        info.setVersion(orderInfo.getVersion());
        int count = logisticsOrderInfoMapper.updateById(info);

        if (count == 0) {
            logger.info("====货运单驳回操作 失败===END===");
            throw new Exception("货运单驳回操作失败");
        }

        String message = String.format(" 订单状态【%s】=>【%s】驳回理由【%s】",
                LogisticsConstant.OrderStatus.getLabel(orderInfo.getStatus()), LogisticsConstant.OrderStatus.getLabel(newStatus), msg);
        // 添加操作记录
        String actionMsg = addOrderProcess(orderInfo.getId(), orderInfo.getNo(), shiroUser, -2,
                "驳回", message, msg, null, true);
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // 判断驳回前是否是待核算状态，若是回滚修改当日统计数据
                        if (orderInfo.getStatus() == LogisticsConstant.OrderStatus.ALREADY_GATHERING && orderInfo.getCreatorId() != 528) {
                            List<OrderProcess> orderProcessList = logisticsOrderProcessMapper.findNewest(orderInfo.getId(), orderInfo.getStatus(), LogisticsConstant.ProcessFlag.NEWEST);
                            DealLogisticsChange dealStatisticsChange = new DealLogisticsChange(
                                    "rejected", orderProcessList.get(0).getCreateTime(), orderInfo.getCreatorId(), orderInfo.getCarId(),
                                    orderInfo.getActualAmount().setScale(2, BigDecimal.ROUND_HALF_DOWN),
                                    orderInfo.getTransportTotal().setScale(3, BigDecimal.ROUND_HALF_DOWN)
                            );
                            // kafka推送
                            kafkaTemplate.send(KafkaTopic.STATISTICS_LOGISTICS_CHANGE, "order", JSONObject.toJSONString(dealStatisticsChange));
                        }
                        // kafka推送
                        sendOrderChange(orderInfo, shiroUser.getRealName() + "驳回了运输单", actionMsg);
                    }
                });
        logger.info("====货运单驳回操作 成功===END===");
    }

    @Override
    public OrderInfo matchSupOrderInfo(String supOrderNo) {
        com.spark.lola.entity.pur.OrderInfo purOrderInfo = supFeignService.findOrderByOrderNo(supOrderNo);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setLineType(LogisticsConstant.OrderLineType.RETURN_CAR);
        orderInfo.setOriginType(LogisticsConstant.OrderOriginType.PURCHASE);
        orderInfo.setProductIds(purOrderInfo.getProductIds());
        orderInfo.setStartAreaIds(purOrderInfo.getStartLocation().getAreaIds());
        orderInfo.setStartArea(purOrderInfo.getStartLocation().getArea());
        orderInfo.setStartAddress(purOrderInfo.getStartLocation().getAddress());
        orderInfo.setEndAreaIds(purOrderInfo.getEndLocation().getAreaIds());
        orderInfo.setEndArea(purOrderInfo.getEndLocation().getArea());
        orderInfo.setEndAddress(purOrderInfo.getEndLocation().getAddress());
        orderInfo.setTransportTotal(purOrderInfo.getQuantity());
//        purOrderInfo.getDetails().forEach(item -> {
//            OrderProduct orderProduct = new OrderProduct();
//            orderProduct.setProductId(item.getProductId());
//            orderProduct.setProductNo(item.getProductNo());
//            orderProduct.setName(item.getName());
//            orderProduct.setWeight(item.getQuantity());
//            orderInfo.getOrderProductList().add(orderProduct);
//        });
        return orderInfo;
    }

    @Override
    public List<SelectMap> selectMap(String key, long createId, int lineType) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id,no");
        queryWrapper.eq("creator_id", createId);
        queryWrapper.eq("line_type", lineType);
        queryWrapper.eq("expenses_exists", LogisticsConstant.ExpensesExists.NO_EXISTS);
        queryWrapper.gt("status", LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS);
        if (!org.springframework.util.StringUtils.isEmpty(key)) {
            queryWrapper.and(o -> o.like("no", key));
        }
        queryWrapper.orderByDesc("update_time");
        List<OrderInfo> lst = baseMapper.selectList(queryWrapper);
        List<SelectMap> selectMaps = new ArrayList<>();
        if (!CollectionUtils.isEmpty(lst)) {
            lst.forEach(item -> {
                selectMaps.add(new SelectMap(item.getId(), item.getNo()));
            });
        }
        return selectMaps;
    }

    @Override
    public OrderCountStatisticVo countStatistic(String type) throws ParseException {
        OrderCountStatisticVo orderCountStatisticVo = new OrderCountStatisticVo();
        Map<String, Date> map = new HashMap<>();
        switch (type) {
            case "today":
                Date date = new Date();
                map = getDate(date, date);
                break;
            case "week":
                map = getDate(getWeek(false), getWeek(true));
                break;
            case "month":
                map = getDate(getMonth(false), getMonth(true));
                break;
        }
        if (CollectionUtils.isEmpty(map)) {
            return orderCountStatisticVo;
        }
        int carNumber = logisticsOrderInfoMapper.countStatistic(1, LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS,
                map.get("startTime"), map.get("endTime"));
        int otherCarNumber = logisticsOrderInfoMapper.countStatistic(2, LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS,
                map.get("startTime"), map.get("endTime"));
        int useReturnCarNumber = logisticsOrderInfoMapper.countStatistic(3, LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS,
                map.get("startTime"), map.get("endTime"));
        int unUseReturnCarNumber = logisticsOrderInfoMapper.countStatistic(4, LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS,
                map.get("startTime"), map.get("endTime"));
        orderCountStatisticVo.setCarNumber(carNumber);
        orderCountStatisticVo.setOtherCarNumber(otherCarNumber);
        orderCountStatisticVo.setUseReturnCarNumber(useReturnCarNumber);
        orderCountStatisticVo.setUnUseReturnCarNumber(unUseReturnCarNumber);
        return orderCountStatisticVo;
    }

    @Override
    public List<OrderStatisticVo> queryDate(String type, Date startTime, Date endTime) {
        List<OrderStatisticVo> allList = logisticsOrderInfoMapper.queryByDate(
                LogisticsConstant.OrderStatus.ALREADY_SHIPMENTS, startTime, endTime);
        allList = allList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
                new TreeSet<>(Comparator.comparing(OrderStatisticVo::getId))
        ), ArrayList::new));
        if (CollectionUtils.isEmpty(allList)) {
            return new ArrayList<>();
        }
        switch (type) {
            case "self":
                return allList.stream()
                        .filter(item -> item.getCreatorId() != 528).collect(Collectors.toList());
            case "other":
                return allList.stream()
                        .filter(item -> item.getCreatorId() == 528).collect(Collectors.toList());
            case "return":
                return allList.stream()
                        .filter(item -> item.getCreatorId() != 528 && item.getLineType() == LogisticsConstant.OrderLineType.RETURN_CAR).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    private Map<String, Date> getDate(Date startDate, Date endDate) throws ParseException {
        // 计算时间
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        DateFormat dateFormat_start = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
        DateFormat dateFormat_end = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
        // 开始时间
        Date startTime = simpleDateFormat.parse(dateFormat_start.format(startDate));
        // 结束时间
        Date endTime = simpleDateFormat.parse(dateFormat_end.format(endDate));
        Map<String, Date> map = new HashMap<>();
        map.put("startTime", startTime);
        map.put("endTime", endTime);
        return map;
    }

    private Date getMonth(boolean isEnd) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        if (!isEnd) {
            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
        } else {
            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        }
        return calendar.getTime();
    }

    private Date getWeek(boolean isEnd) throws ParseException {
        // 计算时间
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.DAY_OF_WEEK, 2);
        if (isEnd) {
            calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + 6);
        }
        return simpleDateFormat.parse(simpleDateFormat.format(calendar.getTime()));
    }

    /**
     * @description: 保存货运单基本信息
     * @param: orderInfo 货运单信息
     * @param: orderNo 货运单号
     * @return: OrderInfo 货运单信息
     * @author: wzp
     * @date: 2020/4/30
     */
    private OrderInfo saveOrderInfo(OrderInfo orderInfo, String orderNo, long creatorId) throws Exception {
        OrderInfo model = new OrderInfo();
        if (orderInfo.getId() != null) {
            model = this.getById(orderInfo.getId());
            // 已完成或废弃禁止修改
            if (model.getStatus() == LogisticsConstant.OrderStatus.ALREADY_COMPLETE ||
                    model.getStatus() == LogisticsConstant.OrderStatus.ALREADY_INVALID) {
                logger.info("====货运单已完成或已废弃禁止修改===END===");
                throw new Exception("货运单已完成或已废弃禁止修改");
            }
            // 非修改项置空
            model.setCreatorId(null);
            model.setCarInfo(null);
            model.setNo(null);
            model.setIsRejected(null);
            model.setExpensesExists(null);
            //禁止修改地址信息
            model.setStartAreaIds(null);
            model.setStartArea(null);
            model.setStartAddress(null);
            model.setEndAreaIds(null);
            model.setEndArea(null);
            model.setEndAddress(null);
            model.setOriginType(null);
            model.setStatus(null);
            // 系统修改项赋值
        } else {
            // 设置初始化项
            model.setCreatorId(creatorId);
            model.setNo(orderNo);
            if (orderInfo.getCreatorId() != null && orderInfo.getCreatorId() == 528L) {
                model.setLineType(null);
                model.setOriginType(null);
            }
        }
        // 添加或修改货运订单
        DataBeanUtils.buildUpdateBean(model, orderInfo);
        logger.info("====保存货运单基本信息===START===");
        if (!this.saveOrUpdate(model)) {
            logger.info("====保存货运单基本信息 失败===END===");
            throw new Exception("货运单基本信息保存失败");
        }
        logger.info("====保存货运单基本信息 成功===END===");
        return model;
    }

    /**
     * @description: 保存货运单商品信息，并获取额外信息回传到货运单表
     * @param: orderProductList 货运单商品集合
     * @param: orderId 货运单id
     * @return: void
     * @author: wzp
     * @date: 2020/4/30
     */
    private OrderInfo saveOrderProduct(List<OrderProduct> orderProductList, long orderId) throws Exception {
        logger.info("====批量保存货运单商品信息===START===");
        // 货运单表中存入的数据
        List<Long> orderProductIds = new ArrayList<>();
        BigDecimal transportTotal = new BigDecimal(0);
        // 获取已存在的商品id集合
        List<Long> oldIdList = logisticsOrderProductMapper.findIdByOrderId(orderId);
        List<Long> idList = new ArrayList<>();
        for (OrderProduct orderProduct : orderProductList) {
            // 绑定货运单
            orderProduct.setOrderId(orderId);
            // 收集前台传入的商品id
            if (orderProduct.getId() != null) {
                idList.add(orderProduct.getId());
            }
            // 获取货运单表需要的数据
            orderProductIds.add(orderProduct.getId());
            // 统计运输量
            transportTotal = transportTotal.add(orderProduct.getWeight());
        }
        boolean flag = logisticsOrderProductService.saveOrUpdateBatch(orderProductList);
        if (!flag) {
            logger.info("====批量保存货运单商品信息 失败===END===");
            throw new Exception("批量保存货运单商品信息失败");
        }
        logger.info("====批量保存货运单商品信息 成功===START===");

        // 批量删除多余项
        logger.info("====批量删除多余货运单商品信息===START===");
        for (Long productId : oldIdList) {
            if (!idList.contains(productId) && !logisticsOrderProductService.removeById(productId)) {
                logger.info("====批量删除多余货运单商品信息 失败===END===");
                throw new Exception("删除多余货运单商品信息失败");
            }
        }
        logger.info("====批量保存货运单商品信息 成功===END===");
        return new OrderInfo(StringUtils.join(orderProductIds, ","), transportTotal);
    }

    /**
     * @description: 增量更新地址信息库
     * @param: locationInfoList 地址信息集合
     * @return: void
     * @author: wzp
     * @date: 2020/4/29
     */
    private void saveLocation(List<LocationInfo> locationInfoList) {
        if (!locationInfoService.saveOrUpdateBatch(locationInfoList)) {
            logger.info("增量更新地址信息库失败");
        }
    }

    /**
     * @description: 重写addOrderProcess原方法
     * @author: wzp
     * @date: 2020/5/9
     */
    private String addOrderProcess(long orderId, String orderNo, ShiroUser shiroUser, int actionCode, String actionName) throws Exception {
        return addOrderProcess(orderId, orderNo, shiroUser, actionCode, actionName, null, null, null, false);
    }

    private String addOrderProcess(long orderId, String orderNo, ShiroUser shiroUser, String actionName, String intro) throws Exception {
        return addOrderProcess(orderId, orderNo, shiroUser, LogisticsConstant.OrderStatus.ALREADY_GATHERING, actionName, null, intro, null, false);
    }

    /**
     * @description: 添加货运单流程记录
     * @param: orderId 货运单id
     * @param: orderNo 货运单号
     * @param: shiroUser 用户信息
     * @param: action 操作编码
     * @param: info 操作信息
     * @return: isRejected 是否是驳回
     * @author: wzp
     * @date: 2020/4/30
     */
    private String addOrderProcess(long orderId, String orderNo, ShiroUser shiroUser, int actionCode, String actionName, String info, String intro, String credentials, boolean isRejected) throws Exception {
        logger.info("====保存货运单操作流程===START===");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowDate = simpleDateFormat.format(new Date());
        if (info == null) {
            info = String.format("员工【%s】%s 进行【%s】操作", shiroUser.getRealName(), nowDate, actionName);
        }
        // 获取最新操作记录
        if (!isRejected) {
            List<OrderProcess> orderProcessList = logisticsOrderProcessMapper.findNewest(orderId, actionCode, LogisticsConstant.ProcessFlag.NEWEST);
            // 更新历史记录
            for (OrderProcess orderProcess : orderProcessList) {
                logger.info("====保存货运单操作流程历史 ===START===");
                OrderProcess process = new OrderProcess();
                process.setId(orderProcess.getId());
                process.setFlag(LogisticsConstant.ProcessFlag.HISTORY);
                process.setVersion(orderProcess.getVersion());
                if (logisticsOrderProcessMapper.updateById(process) == 0) {
                    logger.info("====保存货运单操作流程历史 失败===START===");
                    throw new Exception("保存货运单操作流程历史失败");
                }
                logger.info("====保存货运单操作流程历史 成功===START===");
            }
        }
        // 添加新的操作记录
        OrderProcess orderProcess = new OrderProcess(orderId, orderNo, shiroUser, actionCode, actionName, info, intro, credentials);
        if (logisticsOrderProcessMapper.insert(orderProcess) == 0) {
            logger.info("====保存货运单操作流程 失败===START===");
            throw new Exception("保存货运单操作流程失败");
        }
        logger.info("====保存货运单操作流程 成功===START===");
        return JSONObject.toJSONString(orderProcess);
    }

    private void sendOrderChange(OrderInfo orderInfo, String message, String msg) {
        logger.info("===推送货运订单...");
        OrderDto<OrderInfo> param = new OrderDto<>(OrderType.LOGISTICS_ORDER, orderInfo, msg, message);
        try {
            kafkaTemplate.send(KafkaTopic.LOGISTICS_ORDER_CHANGE, orderInfo.getId().toString(), JSONObject.toJSONString(param));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
